{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Mean variance optimization set up example\n", "\n", "Frans de Ruiter, CQM\n", "For assignment and data, see https://www.fransderuiter.com/JADS/\n", "***" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Setup\n", "Make sure you have installed all the packages listed below, as well as the ipopt solver (see installation instructions from previous class)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import pandas as pd\n", "from pyomo.environ import *\n", "import matplotlib.pyplot as plt\n", "from matplotlib import cm" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Read data" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "data_path = \"https://www.fransderuiter.com/JADS/Meanvariance/MeanVarPortfolio.xlsx\"\n", "# Create pandas table\n", "df_input = pd.read_excel(data_path, sheet_name=0, header=1, skiprows=4, index_col=0)\n", "\n", "# Show table\n", "df_input.head()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": false }, "outputs": [], "source": [ "## Rename the first two columns\n", "\n", "newcolumn_values = df_input.columns.values\n", "newcolumn_values[0] = 'Mean'\n", "newcolumn_values[1] = 'Variance'\n", "\n", "df_input.columns = newcolumn_values\n", "\n", "# Show table with removed column\n", "df_input.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Model parameters" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Set with assets (indices)\n", "assets = df_input.columns[2:] # first two columns are only mean and variance\n", "\n", "# risk parameter\n", "alpha = 0.012" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Plot means and variances of portfolios" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Initialize plot\n", "fig=plt.figure(figsize=(16,16))\n", "\n", "# Plot mean returns and variances of individual assets\n", "plt.scatter([df_input.loc[i,'Variance'] for i in assets], \n", " [100*df_input.loc[i,'Mean'] for i in assets], \n", " s = 200*np.ones(assets.size),\n", " alpha=0.9)\n", "\n", "plt.title(\"Mean-Variance portfolios\")\n", "plt.xlabel(\"Variance\")\n", "plt.ylabel(\"Mean return (\\%)\")\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Model implementation" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Tips:\n", "# acces the mean of asset\n", "i = 'ME1 INV2'\n", "# by:\n", "return_example = df_input.loc[i,'Mean']\n", "\n", "# acces the covariance of two assets by\n", "i = 'ME1 INV2'\n", "j = 'ME1 INV3'\n", "\n", "variance_example = df_input.loc[i,j]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## TODO: fill in the dots\n", "\n", "def MeanVarModelConstruction(alpha,df_input):\n", " # Create model\n", " m = ConcreteModel()\n", "\n", " # TODO: Add variables, objective and constraints to the model. \n", " # In the objective you have to specify the direction (sense): is this a minimization or maximization problem?\n", " \n", " # Variables\n", " m.amount = Var(...) # note that short sellings is not allowed, what does that mean for the range of values that he variable can take?\n", "\n", " # Objective\n", " m.value = Objective(..., sense =...)\n", "\n", " # Constraints on budget\n", " m.budget = Constraint(....)\n", "\n", " return m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Function to solve the model" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def OptimizeMeanVarModel(m,printResults,showprogress = False):\n", " # Optimize\n", " solver = SolverFactory('ipopt') # Take the ipopt solver for nonlinear problems\n", " status = solver.solve(m,tee=showprogress,)\n", "\n", " # Print the status of the solved model\n", " \n", " if printResults:\n", " print(\"Risk aversion parameter = %s \\n\" % alpha)\n", " print(\"Status = %s \\n\" % status.solver.termination_condition)\n", " \n", " obj_opt = value(m.value)\n", " mean_opt = sum([value(m.amount[i]*df_input.loc[i,'Mean']) for i in assets])\n", " variance_opt = sum(df_input.loc[i,j]*value(m.amount[i])*value(m.amount[j]) for i in assets for j in assets)\n", " \n", " return (obj_opt, mean_opt, variance_opt)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plot and show the solution" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Construct model with chosen alpha\n", "m = MeanVarModelConstruction(alpha,df_input)\n", "# Optimize\n", "obj_opt, mean_opt, variance_opt = OptimizeMeanVarModel(m,True,False)\n", "\n", "print(\"Objective value model \\t= %.3f\" % obj_opt)\n", "print(\"\\t Mean return \\t= %.3f\" % mean_opt)\n", "print(\"\\t Variance \\t= %.3f\\n\" % variance_opt)\n", "\n", "print(\"Assets invested in (and amount):\")\n", "print(\"Portfolio composition:\")\n", "for i in assets:\n", " if value(m.amount[i] > 0.0001):\n", " print(\"\\t\"+ i + \" : \\t\" + str(value(m.amount[i]))) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plot the solution" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Initialize plot\n", "fig=plt.figure(figsize=(16,16))\n", "\n", "# Plot mean returns and variances of individual assets\n", "plt.scatter([df_input.loc[i,'Variance'] for i in assets], \n", " [100*df_input.loc[i,'Mean'] for i in assets], \n", " s = 200*np.ones(assets.size),\n", " alpha=0.9)\n", "# Plot mean returns and variances of new optimal portfolio\n", "plt.scatter(variance_opt, \n", " 100*mean_opt, \n", " s = 200*np.ones(assets.size),\n", " c = 'red',\n", " alpha=0.9)\n", "\n", "plt.title(\"Mean-Variance portfolios\")\n", "plt.xlabel(\"Variance\")\n", "plt.ylabel(\"Mean return (\\%)\")\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Bonus question:\n", "Suppose we allow for short selling, short position cannot be more than 10% of your long position. How can we incorporate this in our model?\n", "\n", "Hint 1: First try to write this new constraint on paper before you try to implement it.\n", "\n", "Hint 2: Introduce two new parameters $x_long \\geq 0$ and $x_short \\geq 0$ that indicate the short and long position. So the total position is $x = x_long - x_short$. How do you incorporate the 10% requirement constraint?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# TODO:\n", "# 1) write down the new constraint on paper.\n", "# 2) Make new optimization model for the mean-variance problem that allows for short-selling." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.1" } }, "nbformat": 4, "nbformat_minor": 2 }